#pragma once

#include "Sock.hpp"

#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>

namespace HttpServer
{
    class Server;

    // 线程信息类
    class ThreadData
    {
    public:
        ThreadData(const int& sock, const uint16_t& port, const std::string& ip, Server* psvr)
            :_sock(sock), _port(port), _ip(ip), _psvr(psvr)
        {}

        ~ThreadData()
        {
            close(_sock);
        }

    public:
        int _sock;
        uint16_t _port;
        std::string _ip;
        Server* _psvr; // 回指指针
    };

    class Server
    {
        const static uint16_t default_port = 8888;
        using func_t = function<string(const string&)>;
    public:
        Server(const func_t& func, const uint16_t port = default_port)
            :_func(func), _port(port)
        {}

        void Init()
        {
            _listen_sock.Socket();
            _listen_sock.Bind(_port);
            _listen_sock.Listen();
            logMessage(Debug, "Init Server Success");
        }

        void Start()
        {
            while(true)
            {
                uint16_t clientPort;
                std::string clientIP;
                int clientSock = _listen_sock.Accept(&clientIP, &clientPort);

                // 接受连接失败，重新尝试
                if(clientSock < 0)
                    continue;

                ThreadData* td = new ThreadData(clientSock, clientPort, clientIP, this);
                pthread_t tid;
                pthread_create(&tid, nullptr, threadRoutine, td);
            }
        }

        static void* threadRoutine(void* args)
        {
            pthread_detach(pthread_self());

            ThreadData* td = static_cast<ThreadData*>(args);

            // 假设一次都读完了
            char buff[1024];
            ssize_t test = -1;
            ssize_t s = recv(td->_sock, buff, sizeof(buff) - 1, 0);
            if(s > 0)
            {
                buff[s] = 0;
                std::string response = td->_psvr->_func(buff);
                send(td->_sock, response.c_str(), response.size(), 0);
            }
            else
            {
                logMessage(Debug, "Cilent [%d -> %s:%d] Quit", td->_sock, td->_ip.c_str(), td->_port);
            }

            delete td;
            return nullptr;
        }

        ~Server()
        {
            _listen_sock.Close();
        }

    private:
        uint16_t _port;
        Sock _listen_sock;
        func_t _func;
    };
}